package da.metricscraft.threads;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import da.metricscraft.MetricsCraft;
import da.metricscraft.information.Information;

public class InformationGatherer extends Thread {
	private Stack<Information> processInformations;
	private HashMap<Xmls, Document> xmls = new HashMap<Xmls, Document>();
	private HashMap<Xmls, String> filepaths = new HashMap<Xmls, String>();
	public static InformationGatherer singleton;
	public static InformationGatherer getInstance(){
		if (singleton != null)
			return singleton;
		else return null;
	}
	public enum Xmls{
		BIOMES,
		MOVEMENT,
		PLAYER
	}
	public InformationGatherer(){
		InformationGatherer.singleton = this;
		processInformations = new Stack<Information>();
		filepaths.put(Xmls.BIOMES, "MetricsCraft_biomes.xml");
		filepaths.put(Xmls.PLAYER, "MetricsCraft_player.xml");
		filepaths.put(Xmls.MOVEMENT, "MetricsCraft_movement.xml");
		
		try {
			xmls.put(Xmls.MOVEMENT, DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(filepaths.get(Xmls.MOVEMENT)));
			xmls.put(Xmls.PLAYER, DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(filepaths.get(Xmls.PLAYER)));
			xmls.put(Xmls.BIOMES, DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(filepaths.get(Xmls.BIOMES)));
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			MetricsCraft.log.info("[InformationGatherer][Constructor] " + "Error finding file."); 
		}

		Document current = xmls.get(Xmls.MOVEMENT);
		try {
			createDocument(current, Xmls.MOVEMENT, "movement");
			current = xmls.get(Xmls.BIOMES);
			createDocument(current, Xmls.BIOMES, "biomes");
			current = xmls.get(Xmls.PLAYER);
			createDocument(current, Xmls.PLAYER, "playerlist");
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			MetricsCraft.log.info("[InformationGatherer][Constructor] " + "Error creating new file.");
		}
	}
	private void createDocument(Document current, Xmls xmlname, String elementName)
			throws ParserConfigurationException {
		if (current == null){
			MetricsCraft.log.info("[InformationGatherer][createDocument] Creating " + elementName + ".xml");
			current = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
			xmls.put(xmlname, current);
			Element root = current.createElement(elementName);
			current.appendChild(root);
		}else{
			MetricsCraft.log.info("[InformationGatherer][createDocument] Loading " + elementName + ".xml");
		}
	}
	public Document getXML(Xmls xml){
		return xmls.get(xml);
	}
	@Override
	public void run() {
		while(true){
			if (!processInformations.isEmpty()){
				try{
					processInformations.pop().process(this);
					if (processInformations.isEmpty()){
						writeXml();
					}
				}catch (NullPointerException e){
					Logger.getLogger("Minecraft").info("[InformationGatherer][run] Error getting information: " + e.getMessage());
				}
			}else
				synchronized(this){
					try {
						this.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
		}
	}
	private void writeXml() throws TransformerFactoryConfigurationError {
		for(Entry<Xmls, String> entry : filepaths.entrySet()){
			writeToFile(entry.getKey(), entry.getValue()); 
		}
	}
	private void writeToFile(Xmls xml, String path)
			throws TransformerFactoryConfigurationError {
		File fileToWrite = new File(path);
		Document xmlToWrite = xmls.get(xml);
		try {
			if (!fileToWrite.exists()){
				fileToWrite.createNewFile();
			}
			if(fileToWrite.canWrite()){
				Source source = new DOMSource(xmlToWrite);
				Result result = new StreamResult(fileToWrite);
				Transformer xformer = TransformerFactory.newInstance().newTransformer();
				xformer.transform(source, result);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}


	public synchronized void putInformation(Information o){
		processInformations.push(o);
		this.notify();
	}
}
